package com.sugon.modules.sparepart.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.cait.bpmsuite.api.bpmmodle.BPMProcessInstance;
import com.cait.bpmsuite.api.bpmmodle.BPMResult;
import com.cait.bpmsuite.api.bpmmodle.BPMWorkItem;
import com.sugon.dao.SparePartDao;
import com.sugon.dao.SparePartRequDao;
import com.sugon.entity.SparePartRequDetailEntity;
import com.sugon.entity.SparePartRequEntity;
import com.sugon.entity.vo.SparePartsNeedsPlanCommitEaParam;
import com.sugon.modules.base.model.vo.ProcessProgressConst;
import com.sugon.modules.base.service.impl.AbstractErmsBaseApproveManager;
import com.sugon.modules.sparepart.consts.MaterialBaseConst;
import com.sugon.modules.sparepart.consts.SparePartNeedsPlanProgress;
import com.sugon.modules.sparepart.model.vo.CommonApproveParamVO;
import com.sugon.modules.sparepart.model.vo.SparePartRequDetailVO;
import com.sugon.modules.sparepart.service.ISparepartNeedsPlanManager;
import com.sugon.modules.sys.service.INoticeManager;
import com.sugon.modules.workflow.IWorkFlowManager;
import com.sugon.modules.workflow.consts.OaWorkflowProcesses;
import com.sugon.service.SparePartRequDetailService;
import com.sugon.service.SparePartRequService;
import com.sugon.service.SysOaProcessService;
import com.sugon.utils.ShiroUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.util.Assert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

import static com.sugon.utils.ShiroUtils.getUserName;

/**
 * @author ： YuXD
 * @description： 备件需求计划Manager实现类
 * @date ： 2020-08-29 下午 5:32
 * @version: 1.0
 */
@Slf4j
@Service
public class SparepartNeedsPlanManagerImpl extends AbstractErmsBaseApproveManager implements ISparepartNeedsPlanManager {

    @Autowired
    private SparePartRequService sparePartRequService;
    @Resource
    private SparePartRequDao sparePartRequDao;
    @Autowired
    private SparePartRequDetailService sparePartRequDetailService;
    @Autowired
    private SparePartDao sparePartDao;
    @Autowired
    private IWorkFlowManager workFlowManager;
    @Autowired
    private SysOaProcessService processService;
    @Resource
    private INoticeManager noticeManager;

    @Override
    public String check(CommonApproveParamVO approveParam) {
        // 跳转地址
        String directUrl;
        Integer approveState = approveParam.getState();
        String workItemId = approveParam.getWorkItemId();
        BPMWorkItem bpmWorkItem = workFlowManager.getWorkItemById(workItemId);
        cn.hutool.core.lang.Assert.notNull(bpmWorkItem);
        approveParam.setBpmWorkItem(bpmWorkItem);
        if (MaterialBaseConst.AUDIT_PASSED.equals(approveState)) {
            // 完成工作项，并生成重定向链接
            boolean completeFlag = workFlowManager.completeWorkItem(workItemId);
            cn.hutool.core.lang.Assert.isTrue(completeFlag);
            // 判断当前工作项是否是 “制造处PE业务分管人员审核”工作项，如果是则表示审核通过，则更新领料单状态
            String workItemName = bpmWorkItem.getName();
            if (StrUtil.contains(workItemName, "制造处PE业务")) {
                // 1、执行出库
                SparePartRequEntity spNeedsPlan = sparePartRequService.queryObject(approveParam.getId());
                cn.hutool.core.lang.Assert.notNull(spNeedsPlan);
                spNeedsPlan.setProgress(ProcessProgressConst.PASSED);
                sparePartRequService.update(spNeedsPlan);
            }
            // 审核通过，重定向到下一流程
            directUrl = "/BPMClient/bpmdesktop/missionmanage/Missionredirect.jsf?hideRedo=1&workItemId=" + workItemId;
        } else {
            // 审核不通过，回退到上一流程
            directUrl = "/BPMClient/bpmdesktop/missionmanage/Missionexecute.jsf?workitemId=" + workItemId + "&rollback=true";
        }
        // 记录OA审批结果
        processService.generateProcessHandleRecord(OaWorkflowProcesses.SP_NEEDS_PLAN_EA.getBusType(), approveParam.getId(), bpmWorkItem, approveState, approveParam.getCheckRemark());
        return directUrl;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean commitApprove(SparePartsNeedsPlanCommitEaParam commitEaParam) {
        // 获取领料单信息
        SparePartRequEntity spNeedsPlan = sparePartRequService.queryObject(commitEaParam.getId());
        cn.hutool.core.lang.Assert.notNull(spNeedsPlan, "备件需求计划[{}]不存在", commitEaParam.getId());
        spNeedsPlan.setProgress(ProcessProgressConst.DEPT_APPROVING);
        boolean flag = sparePartRequService.update(spNeedsPlan) > 0;
        if (flag) {
            // 1、一个领料单只可以发起一个流程 在发起新的领料审核时，需要删除之前发起的记录
            String procInstId = spNeedsPlan.getProcInstId();
            if (StrUtil.isNotEmpty(procInstId)) {
                log.info("领料单[{}]之前已发起过领料，需要终止之前流程[{}]，创建新的流程！", spNeedsPlan.getPlanCode(), procInstId);
                boolean bpmResult = workFlowManager.terminateProcessInstance(procInstId);
                log.info("终止领料单[{}]之前发起流程[{}]结果：{}", spNeedsPlan.getPlanCode(), procInstId, JSON.toJSONString(bpmResult));
            }
            // 2、创建流程
            String title = StrUtil.format("{}-{}月度备件需求计划审批", spNeedsPlan.getWorkshopName(), spNeedsPlan.getOrganMonth());
            BPMProcessInstance procInst = workFlowManager.createProcessInstance(OaWorkflowProcesses.SP_NEEDS_PLAN_EA.getProcDefId(), title, ShiroUtils.getUnionId());
            // 如果流程创建不成功，不执行后续流程
            if (procInst == null) {
                log.error("流程创建失败，流程定义ID：{}", OaWorkflowProcesses.SP_NEEDS_PLAN_EA.getProcDefId());
                cn.hutool.core.lang.Assert.notNull(procInst);
            }
            procInstId = procInst.getId();
            cn.hutool.core.lang.Assert.isTrue(StrUtil.isNotEmpty(procInstId));
            // 3、设置流程实例变量用于后续审批：部门业务主管、车间经理、制造处PE分管 审批人员
            workFlowManager.setProcessInstanceRelatedData(procInstId, "zhuguanshenpiren", commitEaParam.getZhuguanshenpirenUnionId());
            workFlowManager.setProcessInstanceRelatedData(procInstId, "chejianjinglishenpiren", commitEaParam.getChejianjinglishenpirenUnionId());
            workFlowManager.setProcessInstanceRelatedData(procInstId, "zhizaochupeshenpiren", commitEaParam.getZhizaochupeshenpirenUnionId());
            try {
                // 4、启动流程
                BPMResult result = workFlowManager.startProcessInstance(procInstId);
                if (result == null || !result.isSuccess()) {
                    log.error("启动[{}]流程失败，失败原因：{}", procInst.getName(), JSON.toJSONString(result));
                    return false;
                }
            } catch (Exception e) {
                log.error("启动[{}]流程时出现异常，异常：{}", procInst.getName(), JSON.toJSONString(e));
            }
            // 5、回填流程实例ID到领料单中
            sparePartRequDao.updateProcInstId(commitEaParam.getId(), procInstId);
            log.info("启动领料单[{}]OA审批流程成功，并更新完领料单中procInstId字段！", spNeedsPlan.getPlanCode());
            // 6、完成由 [1 车间业务分管人员提出申请] 这个工作项
            workFlowManager.completeMyWorkItem(procInstId, ShiroUtils.getUnionId(), "SP_NEED", commitEaParam.getId(), "发起备件需求计划审核！");
        }
        return flag;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean cancel(SparePartRequEntity needsPlan) {
        // 先取出进度
        Integer progress = needsPlan.getProgress();
        needsPlan.setProgress(SparePartNeedsPlanProgress.CANCEL);
        boolean updateFlag = sparePartRequService.update(needsPlan) > 0;
        if (updateFlag) {
            // 如果是已审批中或审批遭拒的 备件需求计划，需要终止审批流程并记录撤销审批记录
            if (CollectionUtil.newArrayList(SparePartNeedsPlanProgress.DEPT_APPROVING, SparePartNeedsPlanProgress.PE_APPROVING, SparePartNeedsPlanProgress.PE2_APPROVING, SparePartNeedsPlanProgress.NOT_PASSED).contains(progress)) {
                // 如果流程实例ID存在，则需要终止OA审批流程
                String procInstId = needsPlan.getProcInstId();
                if (StrUtil.isNotEmpty(procInstId)) {
                    workFlowManager.terminateProcessInstance(procInstId);
                }
                // 生成取消审批工作项处理记录
                BPMWorkItem bpmWorkItem = new BPMWorkItem();
                bpmWorkItem.setName("取消需求计划审批");
                bpmWorkItem.setProcInstId(procInstId);
                processService.generateProcessHandleRecord(OaWorkflowProcesses.SP_NEEDS_PLAN_EA.getBusType(), needsPlan.getId(), bpmWorkItem, 1, StrUtil.format("用户[{}]取消备件需求计划审批", ShiroUtils.getUserRealName()));
            }
        }
        return updateFlag;
    }

    /**
     * cancelTransit
     *
     * @param sparePartRequDetail 备件需求计划条目详情
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean cancelTransit(SparePartRequDetailVO sparePartRequDetail) {
        // 获取取消数目
        int cancelTransitNum = sparePartRequDetail.getTransitNum();
        sparePartRequDetail.setIsCancelTransit(1);
        sparePartRequDetail.setTransitNum(0);
        boolean flag = sparePartRequDetailService.update(sparePartRequDetail) > 0;
        if (flag) {
            // 更新下备件在途数
            sparePartDao.realtimeUpdateTransitNum(sparePartRequDetail.getMaterialCode());
            // 推送取消在途通知
            noticeManager.pushCancelTransitNotice(sparePartRequDetail, getUserName(), cancelTransitNum);
        }
        return flag;
    }

    /**
     * 减少在途数
     *
     * @param sparePartNeedsDetailId 备件需求计划明细项ID
     * @param num                    数目
     * @return
     */
    @Override
    public boolean reduceTransitNum(String sparePartNeedsDetailId, int num) {
        // 校验备件需求计划条目项是否存在
        SparePartRequDetailEntity sparePartRequDetail = sparePartRequDetailService.queryObject(sparePartNeedsDetailId);
        Assert.notNull(sparePartRequDetail, "备件需求计划条目项不存在");
        // 校验入库数不得大于在途数
        int transitNum = sparePartRequDetail.getTransitNum();
        Assert.isTrue(transitNum >= num, "入库数不得大于在途数");
        // 修改入库和在途数
        sparePartRequDetail.setInboundNum(sparePartRequDetail.getInboundNum() + num);
        sparePartRequDetail.setTransitNum(transitNum - num);
        boolean flag = sparePartRequDetailService.update(sparePartRequDetail) > 0;
        if (flag) {
            // 更新安全库存中车间的在途数

            // 更新下备件在途数
            sparePartDao.realtimeUpdateTransitNum(sparePartRequDetail.getMaterialCode());
        }
        return flag;
    }
}
